package com.hs.singleton;

import java.io.*;
import java.lang.reflect.Constructor;

/**
 * @Author: hs 单例模式
 * @Description: jvm加载（数据加载到元空间，堆空间放Class对象）、连接（常量池创建，静态变量设置默认值）、初始化（执行静态语句块）
 * @Date: Create in 19:05 2019/7/28
 */
public class SingletonTest {

    public static final long  testLong = 111111L;
    public static long  testLong1 = 111111L;
    public static String  testLong2;

    public static void main(String[] args) throws Exception {
        /*Class<?> aClass = SingletonTest.class.getClassLoader().loadClass("com.hs.singleton.SingletonInnerClass");
        System.out.println(aClass);
        //Field[] fields = aClass.getFields();//静态语句块也没有执行
        Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true);
        Object o1 = declaredConstructor.newInstance();
        Object o2 = declaredConstructor.newInstance();*/
        /*Class<SingletonInnerClass> singletonInnerClassClass = SingletonInnerClass.class;

        SingletonInnerClass.testMethod();//内部类还没有，被加载
        SingletonInnerClass.getInstance();//使用时加载*/

        //类的初始化
        /*Class<SingletonHungry> singletonHungryClass = SingletonHungry.class;
        String hungry = SingletonHungry.hungry;
        SingletonHungry instance = SingletonHungry.getInstance();
        System.out.println(instance);*/
        /*SingletonEnum instance = SingletonEnum.INSTANCE;
        System.out.println(SingletonEnum.INSTANCE);*/
        //反序列化攻击
        //SingletonDoubleCheck myObject = SingletonDoubleCheck.getInstance();
        //SingletonInnerClass myObject = SingletonInnerClass.getInstance();
        //SingletonEnum myObject = SingletonEnum.INSTANCE;
        //writeObjectTofile(myObject);
        //反射攻击
        //reflect(SingletonEnum.class);
        //类的加载、连接、初始化测试
        //loadClass();
        //只是调用静态final变量不会触发初始化,没有final修饰的话，也会触发
        System.out.println(SingletonInnerClass.testLong);
        System.out.println(SingletonInnerClass.testLong2);
        System.out.println(SingletonInnerClass.FINAL_VALUE_INT);
        //SingletonInnerClass.testMethod();
    }
    private static void loadClass() throws ClassNotFoundException {
        //initialize标识： 加载类、连接后，是否初始化
        //Class.forName("com.hs.singleton.SingletonInnerClass",true,SingletonTest.class.getClassLoader());
        Class.forName("com.hs.singleton.SingletonHungry",true,SingletonTest.class.getClassLoader());
        //SingletonTest.class.getClassLoader().loadClass("com.hs.singleton.SingletonHungry");
    }

    private static void reflect(Class clazz) throws Exception {
        Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
        Constructor declaredConstructor = declaredConstructors[0];
        declaredConstructor.setAccessible(true);
        Object huanghun = declaredConstructor.newInstance("HUANGHUN",5);
        Constructor c = clazz.getDeclaredConstructor(null);
        c.setAccessible(true); // 跳过权限检查
        Object sc3 = c.newInstance();
        Object sc4 = c.newInstance();
        System.out.println(sc3);  // sc3，sc4不是同一个对象
        System.out.println(sc4);
    }
    /**
     * 序列化攻击
     * @param myObject
     * @throws Exception
     */
    private static void writeObjectTofile(Object myObject) throws Exception{
        try {
            FileOutputStream fosRef = new FileOutputStream(new File(
                    "myObjectFile.txt"));
            ObjectOutputStream oosRef = new ObjectOutputStream(fosRef);
            oosRef.writeObject(myObject);
            oosRef.close();
            fosRef.close();
            System.out.println(myObject.hashCode());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            FileInputStream fisRef = new FileInputStream(new File(
                    "myObjectFile.txt"));
            ObjectInputStream iosRef = new ObjectInputStream(fisRef);
            Object myObject2 =  iosRef.readObject();
            iosRef.close();
            fisRef.close();
            System.out.println(myObject2.hashCode());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }


}
